package com.company.myfirstjmixproject.screen.myonboarding;

import com.company.myfirstjmixproject.entity.User;
import com.company.myfirstjmixproject.entity.UserStep;
import io.jmix.core.security.CurrentAuthentication;
import io.jmix.ui.UiComponents;
import io.jmix.ui.component.Button;
import io.jmix.ui.component.CheckBox;
import io.jmix.ui.component.Component;
import io.jmix.ui.component.Label;
import io.jmix.ui.model.CollectionContainer;
import io.jmix.ui.model.CollectionLoader;
import io.jmix.ui.model.DataContext;
import io.jmix.ui.model.InstanceContainer;
import io.jmix.ui.screen.*;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.LocalDate;


/**
 * Copyright(C) 2023 Cardinal Operations. All rights reserved.
 *
 * @author ZhaoBo (zhaobo@shanshu.ai)
 * @date 2023/1/31 11:43 AM
 */
@UiController("MyOnboardingScreen")
@UiDescriptor("my-onboarding-screen.xml")
public class MyOnboardingScreen extends Screen {

    @Autowired
    private CurrentAuthentication currentAuthentication;

    @Autowired
    private CollectionLoader<UserStep> userStepsDl;

    @Autowired
    private UiComponents uiComponents;

    /**
     * 标签
     */
    @Autowired
    private Label totalStepsLabel;

    @Autowired
    private Label completedStepsLabel;

    @Autowired
    private Label overdueStepsLabel;

    /**
     * 集合容器
     */
    @Autowired
    private CollectionContainer<UserStep> userStepsDc;

    @Autowired
    private DataContext dataContext;

    @Subscribe
    public void onBeforeShow(BeforeShowEvent event) {
        User user = (User) currentAuthentication.getUser();

        userStepsDl.setParameter("user", user);
        userStepsDl.load();

        // 界面打开时就会更新这些标签
        updateLabels();

    }

    @Subscribe(id = "userStepsDc", target = Target.DATA_CONTAINER)
    public void onUserStepsDcItemPropertyChange(InstanceContainer.ItemPropertyChangeEvent<UserStep> event) {
        // 当表格中的复选框☑️修改步骤的completedDate属性时，也会更新标签
        updateLabels();
    }


    @Install(to = "userStepsTable.completed", subject = "columnGenerator")
    private Component userStepsTableCompletedColumnGenerator(UserStep userStep) {
        CheckBox checkBox = uiComponents.create(CheckBox.class);
        checkBox.setValue(userStep.getCompletedDate() != null);
        checkBox.addValueChangeListener(e -> {
            if (userStep.getCompletedDate() == null) {
                userStep.setCompletedDate(LocalDate.now());
            } else {
                userStep.setCompletedDate(null);
            }
        });

        return checkBox;
    }

    /**
     * 跟新步骤记录标签
     */
    private void updateLabels() {
        // 总步骤
        totalStepsLabel.setValue("Total steps：" + userStepsDc.getItems().size());

        // 完成的步骤
        long completedCount = userStepsDc.getItems().stream().filter(us -> us.getCompletedDate() != null).count();
        completedStepsLabel.setValue("Completed steps: " + completedCount);

        // 超时的步骤
        long overdueCount = userStepsDc.getItems().stream().filter(us -> isOverdue(us)).count();
        overdueStepsLabel.setValue("Overdue steps: " + overdueCount);

    }

    private boolean isOverdue(UserStep us) {
        return us.getCompletedDate() == null && us.getDueDate() != null && us.getDueDate().isBefore(LocalDate.now());
    }

    @Subscribe("saveButton")
    public void onSaveButtonClick(Button.ClickEvent event) {
        // DataContext会跟踪数据容器中加载实体的变更，当调用commit()方法时，所有对实例的改动都将保存至数据库
        dataContext.commit();

        // close()方法关闭界面，接收一个"输出"对象，可以调用处理器
        close(StandardOutcome.COMMIT);
    }

    /**
     * Install注解该方法是一个代理（delegate）：一个UI组件（这个case中是表格）会在生命周期的某个阶段调用该方法
     * 这个特殊的代理（styleProvider）接收一个实体实例以及单元格展示的属性名称作为参数
     *
     * @param entity 实体实例
     * @param property 单元格展示的属性名称
     * @return String 样式名称styleName
     */
    @Install(to = "userStepsTable", subject = "styleProvider")
    private String userStepsTableStyleProvider(UserStep entity, String property) {

        if ("dueDate".equals(property) && isOverdue(entity)) {
            return "overdue-step";
        }
        return null;
    }

    @Subscribe("discardButton")
    public void onDiscardButtonClick(Button.ClickEvent event) {
        close(StandardOutcome.DISCARD);
    }
}